package gui_layer;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;

import model_layer.Customer;
import model_layer.Sale;
import model_layer.SaleLineItem;
/**
 * Parts of print() function of InvoicePrinter and entire PrintableWrapper class were taken from Internet website 
 * http://stackoverflow.com/questions/14775753/printing-multiple-jtables-as-one-job-book-object-only-prints-1st-table
 * While FramePrinter class is partialy remade PrintUI class from java tutorial located on:
 * http://docs.oracle.com/javase/tutorial/2d/printing/gui.html
 * We do not own these parts of code and we claim no rights to them. 
 * 
 *
 */
public class InvoicePrinter
{
	private Customer customer;
	private Sale sale;
	private final String COMPANY_NAME = "TechnoMag";
	private final String COMPANY_ADDRESS = "Viril and Metodi 24";
	private final String COMPANY_CITY = "Varna";
	private final String COMPANY_ZIPCODE = "BG9000";
	private final String COMPANY_PHONE_NR = "+35 989 509 997";
	private final String COMPANY_CVR = "8328420392";

	
	public InvoicePrinter(Sale s)
	{
		customer = s.getCustomer();
		sale = s;
		
	}
	
	public void print()
	{
		Printable p = make_printable_frame();
		Printable t = make_table();
		try
    	{
	    	PrinterJob printer = PrinterJob.getPrinterJob();
	
	    	
	        //Set 1/2 " margins and orientation
	        PageFormat pf = printer.defaultPage();
	        pf.setOrientation(PageFormat.PORTRAIT);
	        Paper paper = new Paper();
	        double margin = 36; // half inch
	        paper.setImageableArea(margin, margin, paper.getWidth() - margin * 2, paper.getHeight() - margin * 2);
	        pf.setPaper(paper);
	        Book printJob = new Book();
	
	    	int total_pages = 0;
	    	int pages = getNumberOfPages(p, pf);
	    	total_pages += pages;

	    	printJob.append(new PrintableWrapper(p, total_pages), pf, pages);
	    	pages = getNumberOfPages(t, pf);
	    	total_pages += pages;
	    	printJob.append(new PrintableWrapper(t, total_pages), pf, pages);

	        printer.setPageable(printJob);
	        if (printer.printDialog())
	            printer.print();
    	}
    	catch(PrinterException f)
    	{
    		f.printStackTrace();
    	}
	}
	
	public int getNumberOfPages(Printable delegate, PageFormat pageFormat) throws PrinterException 
    {
        Graphics g = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics();
        int numPages = 0;
        while (true) {
            int result = delegate.print(g, pageFormat, numPages);
            if (result == Printable.PAGE_EXISTS) {
                ++numPages;
            } else {
                break;
            }
        }

        return numPages;
    }
	
	private FramePrinter make_printable_frame()
	{
		return new FramePrinter(new InvoiceFrame());
	}
	
	private Printable make_table()
	{
		TableFrame t = new TableFrame();
		t.setVisible(true);
		Printable p = t.get_table().getPrintable(JTable.PrintMode.FIT_WIDTH, null, null);
		t.dispose();
		return p;
	}
	
	/*
	 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
	 *
	 * Redistribution and use in source and binary forms, with or without
	 * modification, are permitted provided that the following conditions
	 * are met:
	 *
	 *   - Redistributions of source code must retain the above copyright
	 *     notice, this list of conditions and the following disclaimer.
	 *
	 *   - Redistributions in binary form must reproduce the above copyright
	 *     notice, this list of conditions and the following disclaimer in the
	 *     documentation and/or other materials provided with the distribution.
	 *
	 *   - Neither the name of Oracle or the names of its
	 *     contributors may be used to endorse or promote products derived
	 *     from this software without specific prior written permission.
	 *
	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
	 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
	 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
	 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
	 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
	 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
	 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
	 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
	 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
	 */
	class FramePrinter implements Printable
	{
		private JFrame frame;
		public FramePrinter(JFrame f)
		{
			frame = f;
		}
		
		@Override
		public int print(Graphics arg0, PageFormat arg1, int arg2) throws PrinterException
		{
			 if (arg2 > 0) { /* We have only one page, and 'page' is zero-based */
		            return NO_SUCH_PAGE;}
			Graphics2D g2d = (Graphics2D)arg0;
	        g2d.translate(arg1.getImageableX(), arg1.getImageableY());
	 
	        /* Now print the window and its visible contents */
	        frame.setVisible(true);
	        frame.getContentPane().print(arg0);
	        frame.dispose();

	        return PAGE_EXISTS;
		}
		
	}
	
	class PrintableWrapper implements Printable
    {
        private Printable delegate;
        private int offset;

        public PrintableWrapper(Printable delegate, int offset) {
            this.offset = offset;
            this.delegate = delegate;
        }

        @Override
        public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
            return delegate.print(graphics, pageFormat, pageIndex-offset);
        }
    }  

	@SuppressWarnings("serial")
	class InvoiceFrame extends JFrame
	{

		private JPanel contentPane;

		public InvoiceFrame()
		{
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			setBounds(100, 100, 450, 363);
			contentPane = new JPanel();
			contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
			setContentPane(contentPane);
			contentPane.setLayout(null);
			Dimension d = new Dimension(120, 14);
			JLabel comp_name = new JLabel(COMPANY_NAME);
			comp_name.setBounds(10, 11, 46, 14);
			comp_name.setSize(d);
			contentPane.add(comp_name);
			
			JLabel com_cvr = new JLabel(COMPANY_CVR);
			com_cvr.setBounds(107, 11, 46, 14);
			com_cvr.setSize(d);
			contentPane.add(com_cvr);
			
			JLabel lblStreet = new JLabel("Street");
			lblStreet.setBounds(10, 36, 46, 14);
			contentPane.add(lblStreet);
			
			JLabel lblCity = new JLabel("City");
			lblCity.setBounds(10, 61, 46, 14);
			contentPane.add(lblCity);
			
			JLabel lblZipCode = new JLabel("Zip code");
			lblZipCode.setBounds(10, 86, 46, 14);
			contentPane.add(lblZipCode);
			
			JLabel lblPhone = new JLabel("Phone");
			lblPhone.setBounds(10, 111, 46, 14);
			contentPane.add(lblPhone);
			
			JLabel lblTo = new JLabel("To");
			lblTo.setBounds(10, 153, 46, 14);
			contentPane.add(lblTo);
			
			JLabel lblStreet_1 = new JLabel("Street");
			lblStreet_1.setBounds(10, 178, 46, 14);
			contentPane.add(lblStreet_1);
			
			JLabel lblCity_1 = new JLabel("City");
			lblCity_1.setBounds(10, 199, 46, 14);
			contentPane.add(lblCity_1);
			
			JLabel lblZipCode_1 = new JLabel("Zip code");
			lblZipCode_1.setBounds(10, 224, 46, 14);
			contentPane.add(lblZipCode_1);
			
			JLabel lblPhone_1 = new JLabel("Phone");
			lblPhone_1.setBounds(10, 249, 46, 14);
			contentPane.add(lblPhone_1);
			
			JLabel company_street = new JLabel(COMPANY_ADDRESS);
			company_street.setBounds(107, 36, 46, 14);
			company_street.setSize(d);
			contentPane.add(company_street);
			
			JLabel company_city = new JLabel(COMPANY_CITY);
			company_city.setSize(d);
			company_city.setBounds(107, 61, 46, 14);
			contentPane.add(company_city);
			
			JLabel company_zipcode = new JLabel(COMPANY_ZIPCODE);
			company_zipcode.setBounds(107, 86, 46, 14);
			company_zipcode.setSize(d);
			contentPane.add(company_zipcode);
			
			JLabel company_phone = new JLabel(COMPANY_PHONE_NR);
			company_phone.setBounds(107, 111, 46, 14);
			company_phone.setSize(d);
			contentPane.add(company_phone);
			
			JLabel cust_name = new JLabel(customer.getName());
			cust_name.setBounds(107, 153, 46, 14);
			cust_name.setSize(d);
			contentPane.add(cust_name);
			
			JLabel cust_street = new JLabel(customer.getAddress());
			cust_street.setBounds(107, 178, 46, 14);
			cust_street.setSize(d);
			contentPane.add(cust_street);
			
			JLabel cust_city = new JLabel(customer.getCity());
			cust_city.setBounds(107, 199, 46, 14);
			cust_city.setSize(d);
			contentPane.add(cust_city);
			
			JLabel cust_zipcode = new JLabel(customer.getZipcode());
			cust_zipcode.setBounds(107, 224, 46, 14);
			cust_zipcode.setSize(d);
			contentPane.add(cust_zipcode);
			
			JLabel cust_phone = new JLabel(customer.getPhone_nr());
			cust_phone.setBounds(107, 249, 46, 14);
			cust_phone.setSize(d);
			contentPane.add(cust_phone);
			
			JLabel lblTotalPrice = new JLabel("Total price");
			lblTotalPrice.setBounds(282, 278, 77, 14);
			contentPane.add(lblTotalPrice);
			
			JLabel total_price_lbl = new JLabel(String.valueOf(sale.getTotal_price()));
			total_price_lbl.setBounds(353, 278, 46, 14);
			total_price_lbl.setSize(d);
			contentPane.add(total_price_lbl);
		}
	}
	
	@SuppressWarnings("serial")
	class TableFrame extends JFrame
	{
		JTable table;
		public TableFrame()
		{
			table = new JTable();
			List<SaleLineItem> items = sale.getItems();
			Object[] column_names = { "Product", "Amount",  "Price" };
			Object[][] filling = new Object[items.size()][3];
			int i = 0;
			for(SaleLineItem item : items)
			{
				filling[i][0] = item.getProduct().getName();
				filling[i][1] = item.getAmount();
				filling[i][2] = item.getPrice();
				i++;
			}
			table.setModel(new DefaultTableModel(filling, column_names));
			table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
			table.getColumnModel().getColumn(0).setMinWidth(260);
			table.getColumnModel().getColumn(1).setMinWidth(40);
			table.getColumnModel().getColumn(2).setMinWidth(80);
			JScrollPane pane = new JScrollPane(table);
			getContentPane().add(pane);
			table.setVisible(true);
			table.repaint();
		}
		
		public JTable get_table()
		{
			return table;
		}
	}

}
